﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Simple.Common.Helpers
{
    public class HolidayHelper
    {
        #region 字段属性
        private static object _syncObj = new object();
        private static HolidayHelper _instance { get; set; }
        private static List<DateModel> cacheDateList { get; set; }
        private HolidayHelper() { }
        /// <summary>
        /// 获得单例对象,使用懒汉式（双重锁定）
        /// </summary>
        /// <returns></returns>
        public static HolidayHelper GetInstance()
        {
            if (_instance == null)
            {
                lock (_syncObj)
                {
                    if (_instance == null)
                    {
                        _instance = new HolidayHelper();
                    }
                }
            }
            return _instance;
        }
        #endregion

        #region 私有方法
        /// <summary>
        /// 读取文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        private string GetFileContent(string filePath)
        {
            string result = "";
            if (File.Exists(filePath))
            {
                result = File.ReadAllText(filePath);
            }
            return result;
        }
        /// <summary>
        /// 获取配置的Json文件
        /// </summary>
        /// <returns>经过反序列化之后的对象集合</returns>
        private List<DateModel> GetConfigList()
        {
            string path = string.Format("{0}/holidayConfig.json", System.AppDomain.CurrentDomain.BaseDirectory);
            string fileContent = GetFileContent(path);
            if (!string.IsNullOrWhiteSpace(fileContent))
            {
                cacheDateList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<DateModel>>(fileContent);
            }
            return cacheDateList;
        }

        /// <summary>
        /// 获取指定年份的数据
        /// </summary>
        /// <param name="year"></param>
        /// <returns></returns>
        public DateModel GetConfigDataByYear(int year)
        {
            if (cacheDateList == null)//取配置数据
                GetConfigList();
            DateModel result = cacheDateList.FirstOrDefault(m => m.Year == year);
            return result;
        }

        /// <summary>
        /// 判断是否为工作日
        /// </summary>
        /// <param name="currDate">要判断的时间</param>
        /// <param name="thisYearData">当前的数据</param>
        /// <returns></returns>
        public bool IsWorkDay(DateTime currDate)
        {
            DateModel thisYearData = GetConfigDataByYear(currDate.Year);
            if (currDate.Year != thisYearData.Year)//跨年重新读取数据
            {
                thisYearData = GetConfigDataByYear(currDate.Year);
            }
            if (thisYearData.Year > 0)
            {
                string date = currDate.ToString("MMdd");
                int week = (int)currDate.DayOfWeek;

                if (thisYearData.Work.IndexOf(date) >= 0)
                {
                    return true;
                }

                if (thisYearData.Holiday.IndexOf(date) >= 0)
                {
                    return false;
                }

                if (week != 0 && week != 6)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 根据指定时间获取法定工作日和节假日
        /// </summary>
        /// <param name="currDate"></param>
        /// <returns></returns>
        public Tuple<List<DateTime>, List<DateTime>> GetWorkDayByTime(DateTime currDate)
        {
            var work = new List<DateTime>();
            var holiday = new List<DateTime>();
            DateModel thisYearData = GetConfigDataByYear(currDate.Year);
            if (currDate.Year != thisYearData.Year)//跨年重新读取数据
            {
                thisYearData = GetConfigDataByYear(currDate.Year);
            }
            if (thisYearData.Year > 0)
            {
                var days = DateTime.DaysInMonth(currDate.Year, currDate.Month);
                for (var i = 1; i <= days; i++)
                {
                    string date = $"{(currDate.Month).ToString().PadLeft(2, '0')}{i.ToString().PadLeft(2, '0')}";
                    DateTime currtime = DateTime.Parse($"{currDate.Year}-{(currDate.Month).ToString().PadLeft(2, '0')}-{i.ToString().PadLeft(2, '0')}");
                    int week = (int)currtime.DayOfWeek;

                    if (thisYearData.Work.IndexOf(date) >= 0)
                    {
                        work.Add(currtime);
                    }

                    if (thisYearData.Holiday.IndexOf(date) >= 0)
                    {
                        holiday.Add(currtime);
                    }

                    if (week != 0 && week != 6)
                    {
                        work.Add(currtime);
                    }
                }
            }

            return new Tuple<List<DateTime>, List<DateTime>>(work, holiday);
        }

        /// <summary>
        /// 根据时间获取工作日
        /// </summary>
        /// <returns></returns>
        public Tuple<List<DateTime>, List<DateTime>> GetWorkDayAndHolidayByMonth(DateTime currDate)
        {
            var work = new List<DateTime>();
            var holiday = new List<DateTime>();
            DateModel thisYearData = GetConfigDataByYear(currDate.Year);
            if (currDate.Year != thisYearData.Year)//跨年重新读取数据
            {
                thisYearData = GetConfigDataByYear(currDate.Year);
            }
            if (thisYearData.Year > 0)
            {
                var days = DateTime.DaysInMonth(currDate.Year, currDate.Month);
                for (var i = 1; i <= days; i++)
                {
                    string date = $"{(currDate.Month).ToString().PadLeft(2, '0')}{i.ToString().PadLeft(2, '0')}";
                    DateTime currtime = DateTime.Parse($"{currDate.Year}-{(currDate.Month).ToString().PadLeft(2, '0')}-{i.ToString().PadLeft(2, '0')}");
                    int week = (int)currtime.DayOfWeek;

                    if (thisYearData.Work.IndexOf(date) >= 0)
                    {
                        work.Add(currtime);
                    }

                    if (thisYearData.Holiday.IndexOf(date) >= 0)
                    {
                        holiday.Add(currtime);
                    }

                    if (week != 0 && week != 6&& thisYearData.Holiday.IndexOf(date) < 0)
                    {
                        work.Add(currtime);
                    }
                }
            }

            return new Tuple<List<DateTime>, List<DateTime>>(work, holiday);
        }
        #endregion

        #region 公共方法
        public void CleraCacheData()
        {
            if (cacheDateList != null)
            {
                cacheDateList.Clear();
            }
        }
        #endregion
    }

    public struct DateModel
    {
        public int Year { get; set; }

        public List<string> Work { get; set; }

        public List<string> Holiday { get; set; }
    }
}
